package gui.mainWindow.ranking;

import gui.mainWindow.MainWindow;

import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;

import javax.swing.BorderFactory;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.ParallelGroup;
import javax.swing.GroupLayout.SequentialGroup;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.LayoutStyle;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;

import table.models.RankingTable;
import tournamentData.ScoresComparator;
import tournamentData.TournamentData;
import core.GuiComponentLabels;
import core.Person;
import dataBase.DbHolder;
import db.newversion.Combination;

public class RankingController implements Observer {

	private final MainWindow window;
	private final long lastUpdate;
	HashMap < Combination, LinkedList < Integer > > splitUpPlayers;
	int PANEL_WIDTH = 1100;
	private List < RankingTable > rankingTables;

	public RankingController(MainWindow mainWindow) {
		this.window = mainWindow;
		DbHolder.getInstance().getArcherData().addObserver(this);
		TournamentData.getInstance().addObserver(this);
		TournamentData.getInstance().getTargetAssignment().addObserver(this);
		this.splitUpPlayers = new HashMap < Combination, LinkedList < Integer > >();
		this.lastUpdate = 0;
		this.rankingTables = new ArrayList < RankingTable >();
	}

	private void splitUpPlayers() {
		this.splitUpPlayers = new HashMap < Combination, LinkedList < Integer > >();

		for (int i = 0; i < TournamentData.getInstance().getAllParticipants().length; i++) {
			int playerID = TournamentData.getInstance().getAllParticipants() [i];
			Person player = DbHolder.getInstance().getArcherData().getById(playerID);
			Combination combination = new Combination(player.getBowCathegory(), player.getAgeClass(), player.getGender());

			if (!this.splitUpPlayers.containsKey(new Combination(player.getBowCathegory(), player.getAgeClass(), player.getGender()))) {
				this.splitUpPlayers.put(combination, new LinkedList < Integer >());
			}
			this.splitUpPlayers.get(combination).add(playerID);
		}
	}

	private void buildRankingTab() {

		this.rankingTables = new ArrayList < RankingTable >();
		this.window.setRankingWrapper(new RankingPanel());
		this.window.getRankingWrapperScrollPane().setViewportView(this.window.getRankingWrapper());

		this.window.getRankingWrapper().setBorder(BorderFactory.createTitledBorder(GuiComponentLabels.RANKING));

		GroupLayout wrapperLayout = new GroupLayout(this.window.getRankingWrapper());
		this.window.getRankingWrapper().setLayout(wrapperLayout);

		{
			this.window.setRankingPanels(new ArrayList < JPanel >());
			this.window.setRankingTables(new ArrayList < RankingTable >());

			ArrayList < Combination > list = this.getCombinations();

			for (int i = 0; i < list.size(); i++) {
				JPanel panel = new JPanel();
				Combination combination = list.get(i);
				panel.setBorder(BorderFactory.createTitledBorder(combination.toString()));

				this.rankingTables.add(new RankingTable());
				RankingTable table = this.rankingTables.get(i);
				{
					try {
						this.buildTable(table, combination);
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (SQLException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}

				GroupLayout panelLayout = new GroupLayout(panel);
				panel.setLayout(panelLayout);

				JScrollPane scrollPane = new JScrollPane();
				{
					scrollPane.setViewportView(table);
					scrollPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
				}

				SequentialGroup panelHorizontal = panelLayout.createSequentialGroup();
				panelHorizontal.addContainerGap();
				panelHorizontal.addComponent(scrollPane, 0, 309, Short.MAX_VALUE);
				panelHorizontal.addContainerGap();
				panelLayout.setHorizontalGroup(panelHorizontal);

				SequentialGroup panelVertical = panelLayout.createSequentialGroup();
				panelVertical.addContainerGap();
				panelVertical.addComponent(scrollPane, GroupLayout.PREFERRED_SIZE, (table.getRowCount() + 2) * 16, GroupLayout.PREFERRED_SIZE);
				panelVertical.addContainerGap();
				panelLayout.setVerticalGroup(panelVertical);

				this.window.getRankingPanels().add(panel);
				this.window.getRankingTables().add(table);
			}

			SequentialGroup wrapperHorizontalSequential = wrapperLayout.createSequentialGroup();
			wrapperHorizontalSequential.addContainerGap();
			ParallelGroup parallelGroup = wrapperLayout.createParallelGroup();
			for (int i = 0; i < this.window.getRankingPanels().size(); i++) {
				parallelGroup.addGroup(wrapperLayout.createSequentialGroup().addComponent(this.window.getRankingPanels().get(i), GroupLayout.PREFERRED_SIZE, this.PANEL_WIDTH,
						GroupLayout.PREFERRED_SIZE));
				parallelGroup.addGroup(GroupLayout.Alignment.LEADING, wrapperLayout.createSequentialGroup());
			}

			wrapperHorizontalSequential.addGroup(parallelGroup);
			wrapperLayout.setHorizontalGroup(wrapperHorizontalSequential);

			SequentialGroup wrapperVerticalSequential = wrapperLayout.createSequentialGroup();
			for (int i = 0; i < this.window.getRankingPanels().size(); i++) {
				wrapperVerticalSequential.addComponent(this.window.getRankingPanels().get(i), GroupLayout.PREFERRED_SIZE, ((this.window.getRankingTables().get(i).getRowCount() + 2) * 16) + 38,
						GroupLayout.PREFERRED_SIZE);
				wrapperVerticalSequential.addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED);
			}
			wrapperVerticalSequential.addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE);

			wrapperLayout.setVerticalGroup(wrapperVerticalSequential);
		}
	}

	/**
	 * builds a table for all persons of a given combination
	 * [Platz,Name+Surname,foreach round,total points,total hits,total
	 * nines,total tens]
	 * @throws SQLException
	 */

	private void buildTable(RankingTable table, Combination combination) throws IOException, SQLException {
		table.setTitle(combination.toString());
		LinkedList < Integer > playerList = this.splitUpPlayers.get(combination);
		Collections.sort(playerList, ScoresComparator.getInstance());

		Person examplePerson = DbHolder.getInstance().getArcherData().getById(playerList.getFirst());
		ArrayList < Object > columnIdentifiers = new ArrayList < Object >();
		columnIdentifiers.add(GuiComponentLabels.RANK);
		columnIdentifiers.add(GuiComponentLabels.NAME);
		columnIdentifiers.add(GuiComponentLabels.CLUB);

		int numberOfRounds = DbHolder
				.getInstance()
				.getArcherData()
				.getNumberOfRounds(TournamentData.getInstance().getGeneralTournamentInformation().getTournamentType(), examplePerson.getBowCathegory(), examplePerson.getAgeClass(),
						examplePerson.getGender());
		for (int i = 1; i <= numberOfRounds; i++) {
			columnIdentifiers.add(GuiComponentLabels.ROUND + " " + i);
		}
		columnIdentifiers.add(GuiComponentLabels.SCORE);
		columnIdentifiers.add(GuiComponentLabels.TENS);
		columnIdentifiers.add(GuiComponentLabels.NINES);
		columnIdentifiers.add(GuiComponentLabels.XS);

		DefaultTableModel model = new DefaultTableModel();
		model.setColumnIdentifiers(columnIdentifiers.toArray());

		for (int i = 0; i < playerList.size(); i++) {
			ArrayList < Object > rowData = new ArrayList < Object >();
			rowData.add(i + 1);

			Person currentPlayer = DbHolder.getInstance().getArcherData().getById(playerList.get(i));
			rowData.add(currentPlayer.getName() + " " + currentPlayer.getSurName());
			rowData.add(currentPlayer.getClub());

			for (int j = 1; j <= numberOfRounds; j++) {
				rowData.add(TournamentData.getInstance().getScore(playerList.get(i)).getPoints(j));
			}
			rowData.add(TournamentData.getInstance().getScore(playerList.get(i)).getTotalPoints());
			rowData.add(TournamentData.getInstance().getScore(playerList.get(i)).getTotalTens());
			rowData.add(TournamentData.getInstance().getScore(playerList.get(i)).getTotalNines());
			rowData.add(TournamentData.getInstance().getScore(playerList.get(i)).getTotalXS());

			model.addRow(rowData.toArray());
		}

		table.setModel(model);
		table.setEnabled(false);
		this.setColumnWidths(table);
	}

	private void setColumnWidths(JTable table) {
		int index = 0;
		int width = 0;
		TableColumn column;

		/** ranking column width */
		column = table.getColumnModel().getColumn(index);
		width = 1;
		column.setPreferredWidth(width);

		/** name column width */
		index++;
		column = table.getColumnModel().getColumn(index);
		width = 150;
		column.setPreferredWidth(width);

		/** club column width */
		index++;
		column = table.getColumnModel().getColumn(index);
		width = 150;
		column.setPreferredWidth(width);

		/** for each round */
		int numberOfRounds = table.getColumnCount() - 7;
		for (int i = 0; i < numberOfRounds; i++) {
			index++;
			column = table.getColumnModel().getColumn(index);
			width = 1;
			column.setPreferredWidth(width);
		}

		/** total points column width */
		index++;
		column = table.getColumnModel().getColumn(index);
		width = 1;
		column.setPreferredWidth(width);

		/** total hits width */
		index++;
		column = table.getColumnModel().getColumn(index);
		width = 1;
		column.setPreferredWidth(width);

		/** total nines column width */
		index++;
		column = table.getColumnModel().getColumn(index);
		width = 1;
		column.setPreferredWidth(width);

		/** total tens column width */
		index++;
		column = table.getColumnModel().getColumn(index);
		width = 1;
		column.setPreferredWidth(width);
	}

	@Override
	public void update(Observable arg0, Object arg1) {
		// long currentTime = System.currentTimeMillis();
		// /** only update if last update was longer ago than 1 second */
		// if ((currentTime - this.lastUpdate) > 1000) {
		this.splitUpPlayers();
		this.buildRankingTab();
		// this.lastUpdate = System.currentTimeMillis();
		// }
	}

	public List < RankingTable > getRankingTables() {
		return this.rankingTables;
	}

	public ArrayList < Combination > getCombinations() {
		Set < Combination > combinations = this.splitUpPlayers.keySet();
		ArrayList < Combination > list = new ArrayList < Combination >(combinations);
		Collections.sort(list);
		return list;
	}
}